#include "networkhandler.h"

#include "zlib.h"
#include "zconf.h"
NetWorkHandler::NetWorkHandler(QObject *parent) : QObject(parent),
    m_tcpSocket(Q_NULLPTR),
    m_ntInfo(Q_NULLPTR),
    m_timerReconnect(Q_NULLPTR)
{
}
void NetWorkHandler::initInfo(DeviceInfo *ntInfo,int type)
{
    m_ntInfo = ntInfo;
    this->m_type = type ;
}
void NetWorkHandler::handleSocketError(QAbstractSocket::SocketError)
{
    qDebug() << m_tcpSocket->errorString();
}
void NetWorkHandler::timerReconnectTick()
{
    if(m_tcpSocket->state() == QAbstractSocket::ConnectedState)
    {
        qDebug()<<"已经连接，停止定时器" ;
        m_timerReconnect->stop();
        return;
    }

    if(m_tcpSocket->state() == QAbstractSocket::ConnectingState)
        m_tcpSocket->abort();
    m_tcpSocket->connectToHost(m_ntInfo->getRemoteHost(),m_ntInfo->getRemotePort());
}
void NetWorkHandler::handleConnected(){
    this->sendHostInfo(m_ntInfo,m_type);
}
void NetWorkHandler::serializeSend(BigPack::Exchange ex){
    std::string s_info ;
    ex.SerializeToString(&s_info);

    if(m_tcpSocket->isOpen()){
        m_tcpSocket->write(intToBytes(ex.ByteSizeLong()),sizeof(qint32));
        m_tcpSocket->write(s_info.c_str(),ex.ByteSizeLong());
        m_tcpSocket->flush();
    }else{
        qFatal("设备没有打开!!!");
    }

}
//第一步，需要发送给服务器通知自己设备消息
void NetWorkHandler::sendHostInfo(DeviceInfo *nt_info,int type){
    //qDebug()<<"注册设备信息";
    BigPack::Exchange ex ;

    ex.set_datatype(BigPack::Exchange::TypeRegisterHost);
    BigPack::CsHostInfo *info = new BigPack::CsHostInfo();
    info->set_cpuid(nt_info->getHashSum(nt_info->getHostMacAddress(),nt_info->getAllPlatformCpuID()).toStdString());
    info->set_mac(nt_info->getHostMacAddress().toStdString());
    info->set_activeorpassive(type);
    ex.set_allocated_hostinfo(info);

    serializeSend(ex);
}
//读取槽函数
void NetWorkHandler::readMessage(){
    ///sender() 方法 可以获取socket
    if(m_tcpSocket->bytesAvailable() <=0)
        return;
    QByteArray buffer  = m_tcpSocket->readAll();
    this->deal(buffer);
}
//创建socket
void NetWorkHandler::createSocket(){

    m_tcpSocket = new QTcpSocket(this);
    connect(m_tcpSocket, &QTcpSocket::stateChanged, this, &NetWorkHandler::socketStateChanged);
    connect(m_tcpSocket, &QTcpSocket::connected, this, &NetWorkHandler::handleConnected);
    connect(m_tcpSocket, &QTcpSocket::readyRead, this, &NetWorkHandler::readMessage);
    connect(m_tcpSocket, SIGNAL(error(QAbstractSocket::SocketError)),
            this, SLOT(handleSocketError(QAbstractSocket::SocketError)));

    //--------------------连接服务器之前 关联处理----------------------
    createToHandler() ;
    //-------------------------------------------------------------
    m_tcpSocket->abort();
    // 连接主机
    m_tcpSocket->connectToHost(m_ntInfo->getRemoteHost(),m_ntInfo->getRemotePort());
    if(!m_timerReconnect)
    {
        m_timerReconnect = new QTimer(this);
        connect(m_timerReconnect, &QTimer::timeout, this, &NetWorkHandler::timerReconnectTick);
    }

}
//需要复写（自定义handler)
void NetWorkHandler::createToHandler(){
    qDebug()<<"NetWorkTransfer::createToHandler";
}
//移除socket
void NetWorkHandler::removeSocket()
{
    if(m_timerReconnect)
    {
        if(m_timerReconnect->isActive())
            m_timerReconnect->stop();

        m_timerReconnect->deleteLater();
        m_timerReconnect = Q_NULLPTR;
    }
    if(m_tcpSocket)
    {
        if(m_tcpSocket->state() != QAbstractSocket::UnconnectedState)
            m_tcpSocket->close();

        m_tcpSocket->disconnectFromHost();
        m_tcpSocket->deleteLater();
        m_tcpSocket = Q_NULLPTR;
    }

    emit finished();
}

//socket状态改变
void NetWorkHandler::socketStateChanged(QAbstractSocket::SocketState state)
{
    switch(state)
    {
    case QAbstractSocket::UnconnectedState:
    {
        //qDebug()<<"Socket::socketStateChanged: 没有连到服务器.";
        if(m_timerReconnect)
            if(!m_timerReconnect->isActive())
                m_timerReconnect->start(5000);
        emit connectedStatus(false);
        break;
    }
    case QAbstractSocket::HostLookupState:
    {
        break;
    }
    case QAbstractSocket::ConnectingState:
    {
        if(m_timerReconnect)
            if(!m_timerReconnect->isActive())
                m_timerReconnect->start(5000);
        break;
    }
    case QAbstractSocket::ConnectedState:
    {
        //qDebug()<<"Socket::socketStateChanged: 已连接到服务器.";
        emit connectedStatus(true);
        break;
    }
    case QAbstractSocket::ClosingState:
    {
        //qDebug()<<"Socket::socketStateChanged: 已断开服务器连接.";
        //关闭传输图片
        emit connectedStatus(false);
        if(m_timerReconnect){
            qInfo()<<"启动定时重连";
            if(!m_timerReconnect->isActive())
                m_timerReconnect->start(5000);
        }
        break;
    }
    default:
    {
        break;
    }
    }
}

//写入的时候，把 int 转化为网络序
QByteArray NetWorkHandler::intToBytes(int n) {
    QByteArray buf;
    buf.resize(4);
    buf[3] = static_cast<quint16> (n & 0xff);
    buf[2] = static_cast<quint16> (n >> 8 & 0xff);
    buf[1] = static_cast<quint16> (n >> 16 & 0xff);
    buf[0] = static_cast<quint16> (n >> 24 & 0xff);
    return buf;
}
//读取回来需要转换
int NetWorkHandler::bytesToInt(QByteArray b) {
    return (b[3] & 0xff) | (b[2] & 0xff) << 8 | (b[1] & 0xff) << 16| (b[0] & 0xff) << 24;
}
//处理协议
void NetWorkHandler::dealProto(int i,BigPack::Exchange resv_exc){
    //virtual复写
    switch(i){
    case BigPack::Exchange::TypeReplyRegisterDetails:{
        if(resv_exc.replyinfo().success()){
            qDebug()<<QString::fromStdString(resv_exc.replyinfo().registerid());
            this->m_transferId = QString::fromStdString(resv_exc.replyinfo().registerid());
        }
        break;
    }
    }
}
//粘包处理
void NetWorkHandler::deal(QByteArray buffer){
    //读取数据放入缓冲区
    m_buffer.append(buffer);
    qint32 pro_len;
    int bufferSize = m_buffer.size();
    while(bufferSize)
    {
        //不够包头数据长度，等下次解析
        if(bufferSize < (int)(sizeof(qint32)*1))
            break;
        //不够数据长度,返回，如果足够，获取协议长度，翻译协议
        pro_len =bytesToInt(m_buffer) ;
        if(bufferSize < pro_len + (int)sizeof(qint32)*1)
            break;
        QByteArray exBuf = m_buffer.mid((int)sizeof(qint32)*1,pro_len);
        BigPack::Exchange resv_exc ;
        //反序列化
        resv_exc.ParseFromString(exBuf.toStdString());
        //----------------------------处理协议------------------------------
        dealProto(resv_exc.datatype(),resv_exc);
        //-----------------------------------------------------------------
        //缓存多余的数据
        buffer = m_buffer.right(bufferSize - pro_len - sizeof(qint32)*1) ;
        //更新长度
        bufferSize = buffer.size();
        //更新多余的数据
        m_buffer = buffer;
    }
}
//压缩处理
QByteArray NetWorkHandler::GzipCompress(QByteArray postBody)
{
    QByteArray outBuf;
    z_stream c_stream;
    //int err = 0;
    //int windowBits = 15;
    int GZIP_ENCODING = 16;
    if (!postBody.isEmpty())
    {
        c_stream.zalloc = (alloc_func)0;
        c_stream.zfree = (free_func)0;
        c_stream.opaque = (voidpf)0;
        c_stream.next_in = (Bytef *)postBody.data();
        c_stream.avail_in = postBody.size();
        if (deflateInit2(&c_stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
                         MAX_WBITS + GZIP_ENCODING, 8, Z_DEFAULT_STRATEGY) != Z_OK) return QByteArray();

        for (;;) {
            char destBuf[4096] = { 0 };
            c_stream.next_out = (Bytef *)destBuf;
            c_stream.avail_out = 4096;
            int err = deflate(&c_stream, Z_FINISH);
            outBuf.append(destBuf, 4096 - c_stream.avail_out);
            if (err == Z_STREAM_END || err != Z_OK)
            {
                break;
            }
        }
        //auto total = c_stream.total_out;
        deflateEnd(&c_stream);
        //total = c_stream.total_out;
    }
    return outBuf;
}
//解压缩
QByteArray NetWorkHandler::GZipUnCompress(QByteArray src)
{
    QByteArray outBuffer;
    z_stream strm;
    strm.zalloc = NULL;
    strm.zfree = NULL;
    strm.opaque = NULL;

    strm.avail_in = src.size();
    strm.next_in = (Bytef *)src.data();

    int err = -1;
    err = inflateInit2(&strm, MAX_WBITS + 16);
    if (err == Z_OK) {
        while (true)
        {
            char buffer[4096] = { 0 };
            strm.avail_out = 4096;
            strm.next_out = (Bytef *)buffer;
            int code = inflate(&strm, Z_FINISH);
            outBuffer.append(buffer, 4096 - strm.avail_out);
            if (Z_STREAM_END == code )
            {
                break;
            }
        }
    }
    inflateEnd(&strm);
    return outBuffer;
}



